#include "EventListUtils.hpp"

#include <iostream>
#include <vector>
#include <exception>

namespace Event
{

List::List()
{
    list_num = 0;
    data_size = 0;
    type = Type::EVENT_TYPE_NONE;
    end = nullptr;
    next = nullptr;
    iter = nullptr;
    data.u64 = 0;
}

List::List(const char *raw)
{
    List *head = NULL, *tmp, *cur;
    auto *p = raw;
    ListState status = ListState::EVENT_LIST_SUCCESS;

    if (raw == NULL)
    {
        List();
        throw std::runtime_error("Construct with nullptr.\n");
    }

    status = complete_check_end(raw);
    if (status != ListState::EVENT_LIST_SUCCESS)
        throw std::runtime_error("Check List end failed.\n");

    list_num = *((uint32_t *)(p + 1));
    if (list_num <= 0)
        throw std::runtime_error("List::list_num <= 0.\n");
    data_size = *((uint32_t *)(p + 5));
    /* p 指向 self::data */
    p += 9;

reload:
    if (*p >= EVENT_TYPE_NONE && *p <= EVENT_TYPE_POINTER)
    {
        status = base_data_pull(&p, &head);
    }
    else if (*p >= EVENT_TYPE_STRING && *p <= EVENT_TYPE_RAW_DATA)
    {
        status = struct_data_pull((eint8 **)&p, &head);
    }
    else if (*p == EVENT_TYPE_LIST)
    {
        tmp = event_list_new_with_raw(EPTR(p));
        if (!tmp)
        {
            printf(_("NULL of create a new EventList Object!\n"));
            goto fatal_and_exit;
        }
        /* 此处需要刷新，tmp->data_size 才会正常 */
        event_list_refresh(tmp);
        cur = event_list_new();
        cur->type = EVENT_TYPE_LIST;
        event_node_set_data(EVENT_NODE(cur), tmp, event_object_unref);
        if (!head)
        {
            head = cur;
        }
        else
        {
            event_node_set_next(EVENT_NODE(head->end),
                EVENT_NODE(cur));
        }
        head->end = cur;
        p += (10 + tmp->data_size);
        status = EVENT_LIST_RELOAD;
    }
    else if (*p == EVENT_TYPE_END)
    {
        status = EVENT_LIST_END_OF_DATA;
    }
    else
    {
        status = EVENT_LIST_PARSER_ERROR;
    }

    if (status == EVENT_LIST_RELOAD)
    {
        goto reload;
    }
    else if (status == EVENT_LIST_END_OF_DATA)
    {
        if (head)
        {
            head->data_size = data_size;
            head->list_num = list_num;
        }
        else
        {
            head = event_list_new();
        }
        return head;
    }
    else if (status == EVENT_LIST_PARSER_ERROR)
    {
        goto fatal_and_exit;
    }

fatal_and_exit:
    event_object_unref(head);
    return NULL;
}

ListState
List::complete_check_end(const char *raw)
{
    auto p = raw;
    uint32_t size;

    if (complete_check_type(raw) != ListState::EVENT_LIST_SUCCESS)
        return EVENT_LIST_TYPE_ERROR;
    p += 5;
    size = *((uint32_t *)p);
    p += (size + 4);

    if (*p != 'L')
        return EVENT_LIST_IMCOMPLETE_ERROR;

    return EVENT_LIST_SUCCESS;
}

ListState
List::complete_check_type(const char *raw)
{
    EventType type = (EventType)(*((uint8_t *)raw));

    if (type != EVENT_TYPE_LIST)
        return EVENT_LIST_TYPE_ERROR;
    return EVENT_LIST_SUCCESS;
}

List::~List()
{
    if (type == Type::EVENT_TYPE_STRING || data.str != nullptr)
        delete data.str;
    else if (type == Type::EVENT_TYPE_LIST || data.lst != nullptr)
        delete data.lst;

    if (next != nullptr)
        delete next;
}

Type
List::get_type()
{
    return type;
}

const TCollect
List::get_data()
{
    return data;
}

#define DEF_ADD_DATA(__type_tp, EVENT_TYPE, __mem) \
void List::add_data(__type_tp _data)\
{\
    List *cur;\
    if (end == nullptr)\
    {\
        end = this;\
        cur = this;\
    }\
    else\
    {\
        auto cur = new List;\
        this->end->next = cur;\
    }\
    cur->type = EVENT_TYPE;\
    cur->data.__mem = _data;\
}

DEF_ADD_DATA(bool, Type::EVENT_TYPE_UINT8, u8)
DEF_ADD_DATA(unsigned char, Type::EVENT_TYPE_UINT8, u8)
DEF_ADD_DATA(char, Type::EVENT_TYPE_INT8, i8)
DEF_ADD_DATA(unsigned short, Type::EVENT_TYPE_UINT16, u16)
DEF_ADD_DATA(short, Type::EVENT_TYPE_INT16, i16)
DEF_ADD_DATA(unsigned int, Type::EVENT_TYPE_UINT32, u32)
DEF_ADD_DATA(int, Type::EVENT_TYPE_INT32, i32)
DEF_ADD_DATA(unsigned long, Type::EVENT_TYPE_UINT64, u64)
DEF_ADD_DATA(long, Type::EVENT_TYPE_INT64, i64)
DEF_ADD_DATA(float, Type::EVENT_TYPE_FLOAT32, f32)
DEF_ADD_DATA(double, Type::EVENT_TYPE_FLOAT64, f64)
DEF_ADD_DATA(void *, Type::EVENT_TYPE_POINTER, ptr)
DEF_ADD_DATA(std::string *, Type::EVENT_TYPE_STRING, str)
DEF_ADD_DATA(List *, Type::EVENT_TYPE_LIST, lst)

void List::add_data(const char *_data)
{
    List *cur;
    if (end == nullptr)
    {
        end = this;
        cur = this;
    }
    else
    {
        auto cur = new List;
        this->end->next = cur;
    }
    cur->type = Type::EVENT_TYPE_STRING;
    cur->data.str = new std::string(_data);
}

void
List::iteration_reset()
{
    iter = this;
}

List *
List::iteration_get()
{
    auto _iter = iter;
    if (_iter != nullptr)
    {
        iter = iter->next;
    }
    return _iter;
}


} // namespace Event

